import * as React from 'react'
import ReactDOM from 'react-dom/client'
import SvgIcon from './SvgIcon'
import type { SvgIconProps } from './SvgIcon'
import { uuid } from '../utils'

export function Loading(
  options: Omit<SvgIconProps, 'name'> & { isCenter?: boolean },
) {
  options = Object.assign(
    {
      // stroke: '#646cff',
      size: 35,
      className: options?.isCenter ? 'center-both' : '',
    },
    options ?? {},
  )

  return (<SvgIcon name="loading" {...options} />) as React.ReactNode
}
// get element uuid, if element without uuid then set a uuid and return
function getElementUUID(element: Element) {
  if (!element) return 'noid'
  const attrkey = 'data-loading-container-uuid'
  let uid = element?.getAttribute(attrkey)
  if (!uid) {
    uid = uuid(16)
    element.setAttribute(attrkey, uid)
  }
  return uid
}
type loadingConfigTypes = {
  inner?: boolean
  mask?: boolean
  maskStyle?: Partial<CSSStyleDeclaration>
}
// eslint-disable-next-line react-refresh/only-export-components
export const showLoading = (function getShowLoading() {
  let isShowing = false
  const closeLoading: Obj<Fn> = {}

  return function openLoading(
    options: SvgIconProps = {} as SvgIconProps,
    loadingAreaDivOrSelector: string | Element = document.body,
    config: loadingConfigTypes = {},
  ) {
    // only one loading
    if (!config.inner && isShowing) {
      return closeLoading[0]
    }

    let loadingAreaDiv: HTMLElement = document.body
    if (typeof loadingAreaDivOrSelector === 'string') {
      loadingAreaDiv = document.querySelector(loadingAreaDivOrSelector)!
    } else {
      loadingAreaDiv = loadingAreaDivOrSelector as HTMLElement
    }
    let containerUUid = ''
    if (config.inner) {
      containerUUid = getElementUUID(loadingAreaDiv)
      if (closeLoading[containerUUid]) return closeLoading[containerUUid]
    }

    let div = document.createElement('div')
    div.className = config.inner ? 'loading-wrapper-inner' : 'loading-wrapper'
    const id = `loading-${Date.now()}-${Math.floor(10000 * Math.random())}`
    div.setAttribute('id', id)

    const locateCenter = () => {
      const rect = loadingAreaDiv?.getBoundingClientRect()
      if (rect) {
        div.style.top = `${
          config.inner ? rect.height / 2 : rect.top + rect.height / 2
        }px`
        div.style.left = `${
          config.inner ? rect.width / 2 : rect.left + rect.width / 2
        }px`
      }
    }

    locateCenter()
    const observer = new ResizeObserver(locateCenter)
    observer.observe(loadingAreaDiv!)

    const loadingContainer = config.inner ? loadingAreaDiv : document.body
    loadingContainer?.append(div)
    if (config.mask) {
      const bg = document.createElement('div')
      bg.className = 'loading-mask-background'
      if (config.maskStyle) {
        for (const prop in config.maskStyle) {
          if (config.maskStyle[prop]) {
            bg.style[prop] = config.maskStyle[prop] as any
          }
        }
      }
      loadingContainer?.append(bg)
    }
    if (config.inner && loadingContainer) {
      const containerPosition = window
        .getComputedStyle(loadingContainer)
        ?.getPropertyValue('position')
      if (containerPosition === 'static') {
        loadingContainer.style.position = 'relative'
      }
    }
    const loadingRoot = ReactDOM.createRoot(div)

    const hideLoading = () => {
      observer.disconnect()
      loadingRoot.unmount()
      const loadingDiv = document.getElementById(id)
      loadingDiv && loadingContainer?.removeChild(loadingDiv)
      const bgDiv = document.querySelector('.loading-mask-background')
      bgDiv && loadingContainer?.removeChild(bgDiv)
      div = null as any
      containerUUid && delete closeLoading[containerUUid]
      isShowing = false
    }

    loadingRoot.render((<Loading {...options} />) as React.ReactNode)
    isShowing = true

    if (config.inner) {
      closeLoading[containerUUid] = hideLoading
    } else {
      closeLoading[0] = hideLoading
    }
    return hideLoading
  }
})()
